package cn.chiship.sdk.third.service;

import cn.chiship.sdk.cache.service.RedisService;
import cn.chiship.sdk.core.base.BaseResult;
import cn.chiship.sdk.core.base.constants.BaseConstants;
import cn.chiship.sdk.core.exception.ExceptionUtil;
import cn.chiship.sdk.core.exception.custom.BusinessException;
import cn.chiship.sdk.core.util.ObjectUtil;
import cn.chiship.sdk.core.util.StringUtil;
import cn.chiship.sdk.core.util.http.HttpUtil;
import cn.chiship.sdk.third.core.common.ThirdConstants;
import cn.chiship.sdk.third.core.dingtalk.vo.DingTalkBaseUserInfoVo;
import cn.chiship.sdk.third.core.dingtalk.vo.DingTalkConnectUserInfoVo;
import cn.chiship.sdk.third.core.dingtalk.vo.DingTalkUserAccessTokenVo;
import cn.chiship.sdk.third.core.model.DingTalkConfigModel;
import cn.chiship.sdk.third.properties.ChishipDingTalkProperties;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 钉钉服务 URL：https://open.dingtalk.com/document/orgapp/api-overview
 *
 * @author lj
 */
@Component
public class DingTalkService {

    protected static final Logger LOGGER = LoggerFactory.getLogger(DingTalkService.class);

    public static final String API_DING_TALK_SERVER_HOST = "https://oapi.dingtalk.com/";

    public static final String API_DING_TALK_API_SERVER_HOST = "https://api.dingtalk.com/";


    private static final String ACCESS_TOKEN = "access_token";

    private DingTalkConfigModel dingTalkConfigModel;

    private String accessToken = null;

    @Resource
    ChishipDingTalkProperties chishipDingTalkProperties;

    @Resource
    RedisService redisService;

    public DingTalkService config() {
        this.dingTalkConfigModel = new DingTalkConfigModel(chishipDingTalkProperties.getAppKey(),
                chishipDingTalkProperties.getAppSecret(), chishipDingTalkProperties.getMiniAppId(),
                chishipDingTalkProperties.getCorpId(), chishipDingTalkProperties.getAgentId());
        return this;
    }

    public DingTalkService config(DingTalkConfigModel dingTalkConfigModel) {
        if (ObjectUtils.isEmpty(dingTalkConfigModel)) {
            LOGGER.info("钉钉实例配置为空，将自动加载默认配置信息");
            return config();
        }
        this.dingTalkConfigModel = dingTalkConfigModel;
        return this;
    }

    public DingTalkService token() {
        BaseResult baseResult = this.getToken();
        if (!baseResult.isSuccess()) {
            throw new BusinessException(baseResult.getData() + "-" + baseResult.getMessage());
        }
        this.accessToken = baseResult.getData().toString();
        return this;
    }

    /**
     * 获取钉钉配置信息
     *
     * @return
     */
    public DingTalkConfigModel getDingTalkConfigModel() {
        return dingTalkConfigModel;
    }

    /**
     * 获取令牌 URL：https://open.dingtalk.com/document/orgapp/call-server-apis
     *
     * @return BaseResult
     */
    public BaseResult getToken() {
        try {
            String getTokenUrl = API_DING_TALK_SERVER_HOST + "gettoken";
            String key = ThirdConstants.REDIS_DING_TALK_ACCESS_TOKEN + ":" + this.dingTalkConfigModel.getAppKey();
            String token = StringUtil.getString(redisService.get(key), null);
            if (!StringUtil.isNullOrEmpty(token)) {
                return BaseResult.ok(token);
            }
            Map<String, Object> query = new HashMap<>(2);
            query.put("appkey", dingTalkConfigModel.getAppKey());
            query.put("appsecret", dingTalkConfigModel.getAppSecret());
            BaseResult baseResult = HttpUtil.getInstance().doGet(getTokenUrl, query);
            baseResult = analysisHttpResponse(baseResult);
            if (!baseResult.isSuccess()) {
                return baseResult;
            }
            JSONObject dataJson = (JSONObject) baseResult.getData();
            token = dataJson.getString(ACCESS_TOKEN);
            long expiresIn = Long.parseLong(dataJson.getString("expires_in"));
            baseResult.setData(token);
            // 提前5分钟过期
            redisService.set(key, token, expiresIn - 5 * 60);
            return baseResult;
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 获取所有部门
     *
     * @return BaseResult
     */
    public BaseResult getDepartmentList() {
        try {
            String getDepListUrl = API_DING_TALK_SERVER_HOST + "department/list";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            query.put("fetch_child", String.valueOf(Boolean.TRUE));
            query.put("id", String.valueOf(1));
            BaseResult baseResult = HttpUtil.getInstance().doGet(getDepListUrl, query);
            return analysisHttpResponse(baseResult);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 创建部门 url:https://open.dingtalk.com/document/orgapp/create-a-department-v2
     *
     * @param name 部门名称
     * @return BaseResult
     */
    public BaseResult departmentCreate(String name) {
        return departmentCreate(name, 1, false);
    }

    /**
     * 创建部门 url:https://open.dingtalk.com/document/orgapp/create-a-department-v2
     *
     * @param name  部门名称
     * @param group 是否创建部门群
     * @return BaseResult
     */
    public BaseResult departmentCreate(String name, Boolean group) {
        return departmentCreate(name, 1, group);
    }

    /**
     * 创建部门 url:https://open.dingtalk.com/document/orgapp/create-a-department-v2
     *
     * @param name     部门名称
     * @param group    是否创建部门群
     * @param parentId 父部门ID，根部门ID为1。
     * @return {"code":200,"data":{"dept_id":962223661},"message":"操作成功","success":true}
     */
    public BaseResult departmentCreate(String name, Integer parentId, Boolean group) {
        try {
            String createDepUrl = API_DING_TALK_SERVER_HOST + "topapi/v2/department/create";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            JSONObject body = new JSONObject();
            body.put("parent_id", parentId);
            body.put("name", name);
            body.put("create_dept_group", group);
            BaseResult baseResult = HttpUtil.getInstance().doPost(createDepUrl, query, body);
            return analysisHttpResponse2(baseResult);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 更新部门 url：https://open.dingtalk.com/document/orgapp/update-a-department-v2
     *
     * @param deptId 部门ID
     * @param name   部门名称
     * @param group  是否创建部门群
     * @return BaseResult
     */
    public BaseResult departmentUpdate(Integer deptId, String name, Boolean group) {
        try {
            String updateDepUrl = API_DING_TALK_SERVER_HOST + "topapi/v2/department/update";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            JSONObject body = new JSONObject();
            body.put("dept_id", deptId);
            body.put("name", name);
            body.put("create_dept_group", group);
            BaseResult baseResult = HttpUtil.getInstance().doPost(updateDepUrl, query, body);
            return analysisHttpResponse2(baseResult);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 删除部门 url：https://open.dingtalk.com/document/orgapp/delete-a-department-v2
     *
     * @param deptId 部门ID
     * @return BaseResult
     */
    public BaseResult departmentDelete(Integer deptId) {
        try {
            String deleteDepUrl = API_DING_TALK_SERVER_HOST + "topapi/v2/department/delete";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            JSONObject body = new JSONObject();
            body.put("dept_id", deptId);
            BaseResult baseResult = HttpUtil.getInstance().doPost(deleteDepUrl, query, body);
            return analysisHttpResponse2(baseResult);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 获取指定部门下用户基本信息分页
     * urL:https://open.dingtalk.com/document/isvapp/queries-the-simple-information-of-a-department-user?spm=ding_open_doc.document.0.0.35454a97RHvoTs
     *
     * @param deptId 部门ID
     * @param page   页码
     * @return BaseResult
     */
    public BaseResult listUserByDept(Integer deptId, Integer page) {
        try {
            String url = API_DING_TALK_SERVER_HOST + "topapi/user/listsimple";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            query.put("dept_id", String.valueOf(deptId));
            query.put("cursor", String.valueOf((page - 1) * 50));
            query.put("size", String.valueOf(50));
            BaseResult baseResult = HttpUtil.getInstance().doGet(url, query);
            return analysisHttpResponse2(baseResult);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 获取指定部门下用户详情分页
     * urL:https://open.dingtalk.com/document/isvapp/queries-the-complete-information-of-a-department-user
     *
     * @param deptId 部门ID
     * @param page   页码
     * @return BaseResult
     */
    public BaseResult listUserDetailByDept(Integer deptId, Integer page) {
        try {
            String url = API_DING_TALK_SERVER_HOST + "topapi/v2/user/list";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            query.put("dept_id", String.valueOf(deptId));
            query.put("cursor", String.valueOf((page - 1) * 50));
            query.put("size", String.valueOf(50));
            BaseResult baseResult = HttpUtil.getInstance().doGet(url, query);
            return analysisHttpResponse2(baseResult);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 根据主键查询详情
     *
     * @param userId
     * @return BaseResult
     */
    public BaseResult getUserById(String userId) {
        try {
            String url = API_DING_TALK_SERVER_HOST + "topapi/v2/user/get";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            Map<String, Object> body = new HashMap<>(2);
            body.put("userid", userId);
            BaseResult baseResult = HttpUtil.getInstance().doPost(url, query, body);
            baseResult = analysisHttpResponse(baseResult);
            if (!baseResult.isSuccess()) {
                return baseResult;
            }
            JSONObject dataJSON = (JSONObject) baseResult.getData();
            baseResult.setData(dataJSON.getJSONObject("result"));
            return baseResult;
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 根据手机号查询详情
     *
     * @param mobile
     * @return BaseResult
     */
    public BaseResult getUserByMobile(String mobile) {

        try {
            String url = API_DING_TALK_SERVER_HOST + "topapi/v2/user/getbymobile";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            Map<String, Object> body = new HashMap<>(2);
            body.put("mobile", mobile);
            BaseResult baseResult = HttpUtil.getInstance().doPost(url, query, body);
            baseResult = analysisHttpResponse(baseResult);
            if (baseResult.isSuccess()) {
                JSONObject dataJSON = (JSONObject) baseResult.getData();
                String userId = dataJSON.getJSONObject("result").getString("userid");
                baseResult = getUserById(userId);
            }
            return baseResult;
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 获取用户通讯录个人信息
     * <a href="https://open.dingtalk.com/document/orgapp/dingtalk-retrieve-user-information">链接</a>
     *
     * @param unionId     用户的unionId, 如需获取当前授权人的信息，unionId参数可以传me。
     * @param accessToken 调用服务端接口的授权凭证。使用个人用户的accessToken
     * @return 结果 BaseResult.ok(DingTalkConnectUserInfoVo)
     */
    public BaseResult getContactUsers(String unionId, String accessToken) {
        try {

            String url = API_DING_TALK_API_SERVER_HOST + "v1.0/contact/users/" + unionId;
            Map<String, String> headers = new HashMap<>(7);
            headers.put("x-acs-dingtalk-access-token", accessToken);
            BaseResult baseResult = HttpUtil.getInstance().headers(headers).doGet(url);
            return analysisHttpResponse3(baseResult, DingTalkConnectUserInfoVo.class);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 根据认证码获取基本用户详情
     * URL:https://open.dingtalk.com/document/orgapp/obtain-the-userid-of-a-user-by-using-the-log-free
     *
     * @param authCode 小程序认证码
     * @return BaseResult
     */
    public BaseResult getBaseUserByAuthCode(String authCode) {

        try {
            String url = API_DING_TALK_SERVER_HOST + "user/getuserinfo";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            query.put("code", authCode);
            BaseResult baseResult = HttpUtil.getInstance().doGet(url, query);

            baseResult = analysisHttpResponse(baseResult);
            if (baseResult.isSuccess()) {
                JSONObject dataJson = (JSONObject) baseResult.getData();
                baseResult.setData(JSON.parseObject(dataJson.toJSONString(), DingTalkBaseUserInfoVo.class));
            }
            return baseResult;

        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }


    /**
     * 根据认证码获取用户详情
     *
     * @param authCode 小程序认证码
     * @return BaseResult
     */
    public BaseResult getUserByAuthCode(String authCode) {

        try {
            BaseResult baseResult = getBaseUserByAuthCode(authCode);
            if (!baseResult.isSuccess()) {
                return baseResult;
            }
            DingTalkBaseUserInfoVo baseUserInfoVo = (DingTalkBaseUserInfoVo) baseResult.getData();
            return getUserById(baseUserInfoVo.getUserId());
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 获得授权二维码链接 第一步
     * URL:<a href="https://open.dingtalk.com/document/orgapp/scan-qr-code-to-log-on-to-third-party-websites">链接</a>
     *
     * @param params
     * @return 结果
     */
    public String getQrConnect(String params) {
        try {
            String redirectUri = chishipDingTalkProperties.getServerDomain() + "/redirectUri/" + dingTalkConfigModel.getAppKey();
            LOGGER.info("redirectUri:{}", redirectUri);
            String authorizeUrl = API_DING_TALK_SERVER_HOST + "connect/qrconnect?appid=APPID&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=REDIRECT_URI";
            String url = authorizeUrl.replace("APPID", dingTalkConfigModel.getAppKey())
                    .replace("REDIRECT_URI", URLEncoder.encode(redirectUri, BaseConstants.UTF8));
            if (StringUtil.isNullOrEmpty(params)) {
                params = "";
            }
            url = url.replace("STATE", params);
            return url;
        } catch (Exception e) {
            throw new BusinessException("获得授权授权二维码认证连接发生错误:" + e.getLocalizedMessage());
        }
    }

    /**
     * 获取登录用户的访问凭证 网页授权第一步
     * <a href="https://open.dingtalk.com/document/orgapp/obtain-identity-credentials">链接</a>
     *
     * @param params
     * @return 结果
     */
    public String getOauth2Auth(String params) {
        try {
            String redirectUri = chishipDingTalkProperties.getServerDomain() + "/redirectUri/" + dingTalkConfigModel.getAppKey();
            LOGGER.info("redirectUri:{}", redirectUri);
            String authorizeUrl = "https://login.dingtalk.com/oauth2/auth?redirect_uri=REDIRECT_URI&response_type=code&client_id=APPID&scope=openid corpid&state=STATE&prompt=consent";
            String url = authorizeUrl.replace("APPID", dingTalkConfigModel.getAppKey())
                    .replace("REDIRECT_URI", URLEncoder.encode(redirectUri, BaseConstants.UTF8));
            if (StringUtil.isNullOrEmpty(params)) {
                params = "";
            }
            url = url.replace("STATE", params);
            return url;
        } catch (Exception e) {
            throw new BusinessException("获取登录用户的访问凭证发生错误:" + e.getLocalizedMessage());
        }
    }

    /**
     * 获取用户token 网页授权第二步
     * <a href="https://open.dingtalk.com/document/orgapp/obtain-user-token">链接</a>
     *
     * @param code
     * @param isRefreshToken 是否OAuth2.0刷新令牌
     * @return 结果 BaseResult.ok(DingTalkUserAccessTokenVo)
     */
    public BaseResult getOauth2AccessToken(String code, Boolean isRefreshToken) {
        try {
            String url = API_DING_TALK_API_SERVER_HOST + "v1.0/oauth2/userAccessToken";
            JSONObject body = new JSONObject();
            body.put("code", code);
            body.put("clientId", dingTalkConfigModel.getAppKey());
            body.put("clientSecret", dingTalkConfigModel.getAppSecret());
            if (Boolean.TRUE.equals(isRefreshToken)) {
                body.put("refreshToken", code);
                body.put("grantType", "refresh_token");
            } else {
                body.put("code", code);
                body.put("grantType", "authorization_code");
            }
            BaseResult baseResult = HttpUtil.getInstance().doPost(url, body);
            return analysisHttpResponse3(baseResult, DingTalkUserAccessTokenVo.class);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 获取当前授权人的信息   网页授权第二步
     * <a href="https://open.dingtalk.com/document/orgapp/obtain-user-token">链接</a>
     *
     * @param accessToken
     * @return 结果 BaseResult.ok(DingTalkConnectUserInfoVo)
     */
    public BaseResult getUserByOauth2AccessToken(String accessToken) {
        return getContactUsers("me", accessToken);
    }

    /**
     * 根据sns临时授权码获取userId
     * URL:https://open.dingtalk.com/document/orgapp/obtain-the-user-information-based-on-the-sns-temporary-authorization
     *
     * @param snsCode 临时授权码
     * @return BaseResult
     */
    public BaseResult getUserIdBySnsCode(String snsCode) {

        try {
            String url = API_DING_TALK_SERVER_HOST + "sns/getuserinfo_bycode";
            Map<String, Object> query = new HashMap<>(2);
            query.put("accessKey", dingTalkConfigModel.getAppKey());
            String timestamp = String.valueOf(System.currentTimeMillis());
            query.put("timestamp", timestamp);
            String appSecret = dingTalkConfigModel.getAppSecret();
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
            byte[] signatureBytes = mac.doFinal(timestamp.getBytes(StandardCharsets.UTF_8));
            String signature = new String(Base64.encodeBase64(signatureBytes));
            query.put("signature", URLDecoder.decode(URLEncoder.encode(signature, "UTF-8"), "UTF-8"));
            Map<String, Object> body = new HashMap<>(2);
            body.put("tmp_auth_code", snsCode);
            BaseResult baseResult = HttpUtil.getInstance().doPost(url, query, body);
            baseResult = analysisHttpResponse(baseResult);
            if (!baseResult.isSuccess()) {
                return baseResult;
            }
            JSONObject datJson = (JSONObject) baseResult.getData();
            datJson = datJson.getJSONObject("user_info");
            String unionId = datJson.getString("unionid");
            String openId = datJson.getString("openid");
            datJson.remove("openid");
            datJson.remove("unionid");
            baseResult = getUserIdByUnionId(unionId);
            if (!baseResult.isSuccess()) {
                return baseResult;
            }
            datJson.put("openId", openId);
            datJson.put("unionId", unionId);
            datJson.put("userId", baseResult.getData());
            baseResult.setData(datJson);
            return baseResult;
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 根据sns临时授权码获取用户信息
     *
     * @param snsCode 临时授权码
     * @return BaseResult
     */
    public BaseResult getUserBySnsCode(String snsCode) {
        try {
            BaseResult baseResult = getUserIdBySnsCode(snsCode);
            if (!baseResult.isSuccess()) {
                return baseResult;
            }
            JSONObject dataJson = (JSONObject) baseResult.getData();
            String userId = dataJson.getString("userId");
            String openId = dataJson.getString("openId");
            baseResult = getUserById(userId);
            if (!baseResult.isSuccess()) {
                return baseResult;
            }
            dataJson = (JSONObject) baseResult.getData();
            dataJson.put("openId", openId);
            baseResult.setData(dataJson);
            return baseResult;
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }


    /**
     * 根据unionid获取用户userid
     * URL:https://open.dingtalk.com/document/orgapp/query-a-user-by-the-union-id
     *
     * @param unionId 员工在当前开发者企业账号范围内的唯一标识，系统生成，不会改变。
     * @return BaseResult
     */
    public BaseResult getUserIdByUnionId(String unionId) {

        try {
            String url = API_DING_TALK_SERVER_HOST + "/topapi/user/getbyunionid";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            Map<String, Object> body = new HashMap<>(2);
            body.put("unionid", unionId);
            BaseResult baseResult = HttpUtil.getInstance().doPost(url, query, body);
            baseResult = analysisHttpResponse(baseResult);
            if (baseResult.isSuccess()) {
                JSONObject dataJson = (JSONObject) baseResult.getData();
                String userId = dataJson.getJSONObject("result").getString("userid");
                return BaseResult.ok(userId);
            }
            return baseResult;
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 根据unionid获取用户信息
     *
     * @param unionId 员工在当前开发者企业账号范围内的唯一标识，系统生成，不会改变。
     * @return BaseResult
     */
    public BaseResult getUserByUnionId(String unionId) {
        try {
            BaseResult baseResult = getUserIdByUnionId(unionId);
            if (!baseResult.isSuccess()) {
                return baseResult;
            }
            return getUserById(baseResult.getData().toString());
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }


    /**
     * 分页获取角色
     *
     * @return BaseResult
     */
    public BaseResult getRoleList(int page) {
        try {
            String url = API_DING_TALK_SERVER_HOST + "topapi/role/list";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            query.put("offset", String.valueOf((page - 1) * 50));
            query.put("size", String.valueOf(50));
            BaseResult baseResult = HttpUtil.getInstance().doGet(url, query);
            return analysisHttpResponse(baseResult);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 获取角色下用户分页
     *
     * @param roleId
     * @param page
     * @return BaseResult
     */
    public BaseResult getRoleUserPage(Long roleId, int page) {
        try {
            String url = API_DING_TALK_SERVER_HOST + "topapi/role/simplelist";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            query.put("role_id", String.valueOf(roleId));
            query.put("offset", String.valueOf((page - 1) * 50));
            query.put("size", String.valueOf(50));
            BaseResult baseResult = HttpUtil.getInstance().doGet(url, query);
            return analysisHttpResponse(baseResult);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 创建群 url：https://open.dingtalk.com/document/orgapp/create-group-session
     *
     * @param name    群名称
     * @param owner   群主
     * @param userIds 群成员
     * @return {"code":200,"data":{"errcode":0,"chatid":"chat6db2407366a30e0d465a6b976b702c47","conversationTag":2,"errmsg":"ok","openConversationId":"cidlWNl7q1px7Jr3fHnQlxXUg=="},"message":"操作成功","success":true}
     */
    public BaseResult chatV1Create(String name, String owner, List<String> userIds) {
        try {
            String createChatUrl = API_DING_TALK_SERVER_HOST + "chat/create";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            JSONObject body = new JSONObject();
            body.put("name", name);
            body.put("owner", owner);
            body.put("useridlist", userIds);
            BaseResult baseResult = HttpUtil.getInstance().doPost(createChatUrl, query, body);
            return analysisHttpResponse(baseResult);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 更新群 url：https://open.dingtalk.com/document/orgapp/create-group-session
     *
     * @param chatId        群标识
     * @param name          群名称
     * @param addUserIds    添加群成员
     * @param removeUserIds 删除群成员
     * @return BaseResult
     */
    public BaseResult chatV1Update(String chatId, String name, List<String> addUserIds, List<String> removeUserIds) {
        try {
            String updateChatUrl = API_DING_TALK_SERVER_HOST + "chat/update";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            JSONObject body = new JSONObject();
            body.put("chatid", chatId);
            body.put("name", name);
            if (ObjectUtil.isNotEmpty(addUserIds)) {
                body.put("add_useridlist", addUserIds);
            }
            if (ObjectUtil.isNotEmpty(removeUserIds)) {
                body.put("del_useridlist", removeUserIds);
            }
            BaseResult baseResult = HttpUtil.getInstance().doPost(updateChatUrl, query, body);
            return analysisHttpResponse(baseResult);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    /**
     * 获取群二维码 url：https://open.dingtalk.com/document/orgapp/obtain-a-qr-code-link
     *
     * @param chatId 群标识
     * @param userId 用户标识
     * @return BaseResult
     */
    public BaseResult chatV1GetQRCode(String chatId, String userId) {
        try {
            String updateChatUrl = API_DING_TALK_SERVER_HOST + "topapi/chat/qrcode/get";
            Map<String, Object> query = new HashMap<>(2);
            query.put(ACCESS_TOKEN, this.getAccessToken());
            JSONObject body = new JSONObject();
            body.put("chatid", chatId);
            body.put("userid", userId);
            BaseResult baseResult = HttpUtil.getInstance().doPost(updateChatUrl, query, body);
            return analysisHttpResponse2(baseResult);
        } catch (Exception e) {
            return ExceptionUtil.formatException(e);
        }
    }

    public BaseResult getReportList(String templateName, Integer day, String userId) {
        try {
            String url = API_DING_TALK_SERVER_HOST + "topapi/report/list";
            Map<String, Object> query = new HashMap<>(2);
            if (null == templateName) {
                templateName = "日报";
            }

            if (null == day) {
                day = 1;
            }

            query.put(ACCESS_TOKEN, this.getAccessToken());
            query.put("start_time", String.valueOf(System.currentTimeMillis() - (day * 24 * 60 * 60 * 1000)));
            query.put("end_time", String.valueOf(System.currentTimeMillis()));
            query.put("template_name", templateName);
            if (null != userId) {
                query.put("userid", userId);
            }

            query.put("cursor", String.valueOf(0));
            query.put("size", String.valueOf(50));
            BaseResult baseResult = HttpUtil.getInstance().doGet(url, query);
            return analysisHttpResponse(baseResult);
        } catch (Exception var6) {
            return ExceptionUtil.formatException(var6);
        }
    }

    /**
     * 发送消息到指定用户
     *
     * @param userId
     * @param msgJSON
     * @return BaseResult
     */
    public BaseResult sendMsgToUser(String userId, JSONObject msgJSON) {
        Map<String, String> query = new HashMap<>(2);
        query.put(ACCESS_TOKEN, this.getAccessToken());
        msgJSON.put("touser", userId);
        msgJSON.put("agentid", dingTalkConfigModel.getAgentId());
        String url = "https://oapi.dingtalk.com/message/send?access_token=" + this.getAccessToken();
        return doPost(url, msgJSON);
    }

    /**
     * 发送通知消息到指定用户
     * URL：https://open.dingtalk.com/document/orgapp/asynchronous-sending-of-enterprise-session-messages
     *
     * @param userId
     * @param msgJSON
     * @return BaseResult
     */
    public BaseResult sendNoticeMsgToUser(String userId, JSONObject msgJSON) {
        return sendNoticeMsgToUser(Arrays.asList(userId), msgJSON);
    }

    /**
     * 发送通知消息到指定用户
     * URL：https://open.dingtalk.com/document/orgapp/asynchronous-sending-of-enterprise-session-messages
     *
     * @param userIds
     * @param msgJSON
     * @return BaseResult
     */
    public BaseResult sendNoticeMsgToUser(List<String> userIds, JSONObject msgJSON) {
        if (userIds.isEmpty()) {
            return BaseResult.error("消息接收人不能为空！");
        }
        Map<String, String> query = new HashMap<>(2);
        query.put(ACCESS_TOKEN, this.getAccessToken());
        JSONObject body = new JSONObject();
        body.put("userid_list", String.join(",", userIds));
        body.put("agent_id", dingTalkConfigModel.getAgentId());
        body.put("to_all_user", false);
        body.put("msg", msgJSON);
        String url = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token="
                + this.getAccessToken();
        return doPost(url, body);
    }

    /**
     * 发送通知消息到指定部门
     * URL：https://open.dingtalk.com/document/orgapp/asynchronous-sending-of-enterprise-session-messages
     *
     * @param dept
     * @param msgJSON
     * @return BaseResult
     */
    public BaseResult sendNoticeMsgToDept(String dept, JSONObject msgJSON) {
        return sendNoticeMsgToDept(Arrays.asList(dept), msgJSON);
    }

    /**
     * 发送通知消息到指定部门
     * URL：https://open.dingtalk.com/document/orgapp/asynchronous-sending-of-enterprise-session-messages
     *
     * @param depts
     * @param msgJSON
     * @return BaseResult
     */
    public BaseResult sendNoticeMsgToDept(List<String> depts, JSONObject msgJSON) {
        if (depts.isEmpty()) {
            return BaseResult.error("消息接收部门不能为空！");
        }
        Map<String, String> query = new HashMap<>(2);
        query.put(ACCESS_TOKEN, this.getAccessToken());
        JSONObject body = new JSONObject();
        body.put("dept_id_list", String.join(",", depts));

        body.put("agent_id", dingTalkConfigModel.getAgentId());
        body.put("to_all_user", false);
        body.put("msg", msgJSON);
        String url = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token="
                + this.getAccessToken();
        return doPost(url, body);
    }

    /**
     * 发送通知消息到整个企业
     * URL：https://open.dingtalk.com/document/orgapp/asynchronous-sending-of-enterprise-session-messages
     *
     * @param msgJSON
     * @return BaseResult
     */
    public BaseResult sendNoticeMsgToCompany(JSONObject msgJSON) {
        Map<String, String> query = new HashMap<>(2);
        query.put(ACCESS_TOKEN, this.getAccessToken());
        JSONObject body = new JSONObject();
        body.put("agent_id", dingTalkConfigModel.getAgentId());
        body.put("to_all_user", true);
        body.put("msg", msgJSON);
        String url = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token="
                + this.getAccessToken();
        return doPost(url, body);
    }

    /**
     * 发送消息到指定群
     *
     * @param chatId
     * @param msgJSON
     * @return BaseResult
     */
    public BaseResult sendMsgToGroup(String chatId, JSONObject msgJSON) {
        Map<String, String> query = new HashMap<>(2);
        query.put(ACCESS_TOKEN, this.getAccessToken());
        JSONObject body = new JSONObject();
        body.put("chatid", chatId);
        body.put("agent_id", dingTalkConfigModel.getAgentId());
        body.put("to_all_user", "true");
        body.put("msg", msgJSON);
        String url = "https://oapi.dingtalk.com/chat/send?access_token=" + this.getAccessToken();
        return doPost(url, body);

    }

    public String getAccessToken() {
        if (StringUtil.isNullOrEmpty(this.accessToken)) {
            throw new BusinessException("token为空！请链式调用如下方法：config().token()获得Token");
        } else {
            return this.accessToken;
        }
    }

    private BaseResult analysisHttpResponse(BaseResult baseResult) {
        if (!baseResult.isSuccess()) {
            return baseResult;
        }
        Integer successStatus = 0;
        String errCode = "errcode";
        String errMsg = "errmsg";
        JSONObject json = JSON.parseObject(StringUtil.getString(baseResult.getData()));
        if (successStatus.equals(json.getInteger(errCode))) {
            return BaseResult.ok(json);
        }
        return BaseResult.error("【" + json.getInteger(errCode) + "】：" + json.getString(errMsg));
    }

    private BaseResult analysisHttpResponse2(BaseResult baseResult) {
        if (!baseResult.isSuccess()) {
            return baseResult;
        }
        Integer successStatus = 0;
        String errCode = "errcode";
        String errMsg = "errmsg";
        JSONObject json = JSON.parseObject(StringUtil.getString(baseResult.getData()));
        if (successStatus.equals(json.getInteger(errCode))) {
            return BaseResult.ok(json.get("result"));
        }
        return BaseResult.error("【" + json.getInteger(errCode) + "】：" + json.getString(errMsg));
    }

    private BaseResult analysisHttpResponse3(BaseResult baseResult, Class c) {
        if (baseResult.isSuccess()) {
            try {
                if (StringUtil.isNull(c)) {
                    return BaseResult.ok(JSON.parseObject(baseResult.getData().toString()));
                }
                return BaseResult.ok(JSON.parseObject(baseResult.getData().toString(), c));
            } catch (Exception e) {
                return baseResult;
            }
        }
        JSONObject dataJson = JSON.parseObject(baseResult.getData().toString());
        return BaseResult.error("【" + dataJson.getString("code") + "】：" + dataJson.getString("message"));
    }

    /**
     * 发送post请求
     *
     * @param url      请求接口
     * @param bodyJson body体
     * @return BaseResult
     */
    private BaseResult doPost(String url, JSONObject bodyJson) {
        try {
            BaseResult baseResult = BaseResult.ok();
            HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            conn.setDoOutput(true);
            String jsonMessage = bodyJson.toJSONString();
            System.out.println(jsonMessage);
            try (OutputStream os = conn.getOutputStream()) {
                byte[] input = jsonMessage.getBytes(StandardCharsets.UTF_8);
                os.write(input, 0, input.length);
            }
            int responseCode = conn.getResponseCode();
            if (responseCode == 200) {
                InputStream is = conn.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String str;
                while ((str = br.readLine()) != null) {
                    baseResult = analysisHttpResponse(BaseResult.ok(str));
                }
                br.close();
            } else {
                baseResult = BaseResult.error("消息发送失败，HTTP响应码：" + responseCode);
            }
            conn.disconnect();
            return baseResult;

        } catch (Exception e) {
            e.printStackTrace();
            return ExceptionUtil.formatException(e);
        }
    }

}
